{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# [JavaScript Array 对象 by RUNOOB](https://www.runoob.com/jsref/jsref-obj-array.html)\n",
    "\n",
    "<details><summary>数组属性</summary>\n",
    "\n",
    "|属性|描述|\n",
    "|:---|:---|\n",
    "|constructor|\t返回创建数组对象的原型函数。|\n",
    "|length|\t设置或返回数组元素的个数。|\n",
    "|prototype|\t允许你向数组对象添加属性或方法。|\n",
    "</details>\n",
    "\n",
    "<details><summary>Array 对象方法</summary>\n",
    "    \n",
    "|方法|描述|\n",
    "|:---|:---|\n",
    "|concat()|\t连接两个或更多的数组，并返回结果。|\n",
    "|copyWithin()|\t从数组的指定位置拷贝元素到数组的另一个指定位置中。|\n",
    "|entries()|\t返回数组的可迭代对象。|\n",
    "|every()|\t检测数值元素的每个元素是否都符合条件。|\n",
    "|fill()|\t使用一个固定值来填充数组。|\n",
    "|filter()|\t检测数值元素，并返回符合条件所有元素的数组。|\n",
    "|find()|\t返回符合传入测试（函数）条件的数组元素。|\n",
    "|findIndex()|\t返回符合传入测试（函数）条件的数组元素索引。|\n",
    "|forEach()|\t数组每个元素都执行一次回调函数。|\n",
    "|from()|\t通过给定的对象中创建一个数组。|\n",
    "|includes()|\t判断一个数组是否包含一个指定的值。|\n",
    "|indexOf()|\t搜索数组中的元素，并返回它所在的位置。|\n",
    "|isArray()|\t判断对象是否为数组。|\n",
    "|join()|\t把数组的所有元素放入一个字符串。|\n",
    "|keys()|\t返回数组的可迭代对象，包含原始数组的键(key)。|\n",
    "|lastIndexOf()|\t搜索数组中的元素，并返回它最后出现的位置。|\n",
    "|map()|\t通过指定函数处理数组的每个元素，并返回处理后的数组。|\n",
    "|pop()|\t删除数组的最后一个元素并返回删除的元素。|\n",
    "|push()|\t向数组的末尾添加一个或更多元素，并返回新的长度。|\n",
    "|reduce()|\t将数组元素计算为一个值（从左到右）。|\n",
    "|reduceRight()|\t将数组元素计算为一个值（从右到左）。|\n",
    "|reverse()|\t反转数组的元素顺序。|\n",
    "|shift()|\t删除并返回数组的第一个元素。|\n",
    "|slice()|\t选取数组的一部分，并返回一个新数组。|\n",
    "|some()|\t检测数组元素中是否有元素符合指定条件。|\n",
    "|sort()|\t对数组的元素进行排序。|\n",
    "|splice()|\t从数组中添加或删除元素。|\n",
    "|toString()|\t把数组转换为字符串，并返回结果。|\n",
    "|unshift()|\t向数组的开头添加一个或更多元素，并返回新的长度。|\n",
    "|valueOf()|\t返回数组对象的原始值。|\n",
    "    \n",
    "`filter()` 方法创建一个新的数组，新数组中的元素是通过检查指定数组中符合条件的所有元素。\n",
    "\n",
    "**注意**： filter() 不会对空数组进行检测。\n",
    "\n",
    "**注意**： filter() 不会改变原始数组。\n",
    "```js\n",
    "array.filter(function(currentValue,index,arr), thisValue)\n",
    "```\n",
    "    \n",
    "- function(currentValue, index,arr)\t必须。函数，数组中的每个元素都会执行这个函数\n",
    "    - currentValue\t必须。当前元素的值\n",
    "    - index\t可选。当前元素的索引值\n",
    "    - arr\t可选。当前元素属于的数组对象\n",
    "- thisValue\t可选。对象作为该执行回调时使用，传递给函数，用作 \"this\" 的值。如果省略了 thisValue ，\"this\" 的值为 \"undefined\"\n",
    "</details>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Beginner"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [all](https://www.30secondsofcode.org/js/s/all)\n",
    "JavaScript, Array, Function, Beginner\n",
    "\n",
    "Returns `true` if the provided predicate function returns `true` for all elements in a collection, `false` otherwise.\n",
    "\n",
    "Use `Array.prototype.every()` to test if all elements in the collection return true based on `fn`. Omit the second argument, `fn`, to use `Boolean` as a default.\n",
    "\n",
    "---\n",
    "every()与some()方法都是JS中数组的迭代方法。\n",
    "\n",
    "- every()是对数组中每一项运行给定函数，如果该函数所有一项返回true,则返回true。一旦有一项不满足则返回flase\n",
    "- some()是对数组中每一项运行给定函数，如果该函数满足任一项返回true，则返回true\n",
    "\n",
    "**语法**\n",
    "```js\n",
    "array.every(function(currentValue,index,arr), thisValue)\n",
    "```\n",
    "\n",
    "**参数说明**\n",
    "- `function(currentValue, index,arr)`\t必须。函数，数组中的每个元素都会执行这个函数\n",
    "- `thisValue`\t可选。对象作为该执行回调时使用，传递给函数，用作 \"this\" 的值。如果省略了 thisValue ，\"this\" 的值为 \"undefined\"\n",
    "    - `currentValue`\t必须。当前元素的值\n",
    "    - `index`\t可选。当前元素的索引值\n",
    "    - `arr`\t可选。当前元素属于的数组对象\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.331921Z",
     "start_time": "2020-11-30T14:44:13.107Z"
    }
   },
   "outputs": [],
   "source": [
    "const all = (arr, fn = Boolean) => arr.every(fn);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.341892Z",
     "start_time": "2020-11-30T14:44:13.114Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "false\n",
      "true\n"
     ]
    }
   ],
   "source": [
    "console.log(all([1, 2, 3], x => x > 1));\n",
    "console.log(all([1, 2, 3]));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [allEqual](https://www.30secondsofcode.org/js/s/all-equal)\n",
    "JavaScript, Array, Function, Beginner\n",
    "\n",
    "Check if all elements in an array are equal.\n",
    "\n",
    "Use `Array.prototype.every()` to check if all the elements of the array are the same as the first one. Elements in the array are compared using the strict comparison operator, which does not account for `NaN` self-inequality."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.354163Z",
     "start_time": "2020-11-30T14:44:13.120Z"
    }
   },
   "outputs": [],
   "source": [
    "const allEqual = arr => arr.every(val => val === arr[0]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.356177Z",
     "start_time": "2020-11-30T14:44:13.124Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "false\n",
      "true\n"
     ]
    }
   ],
   "source": [
    "console.log(allEqual([1, 2, 3, 4, 5, 6]));\n",
    "console.log(allEqual([1, 1, 1, 1]));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [any](https://www.30secondsofcode.org/js/s/any)\n",
    "JavaScript, Array, Function, Beginner\n",
    "\n",
    "Returns `true` if the provided predicate function returns `true` for at least one element in a collection, `false` otherwise.\n",
    "\n",
    "Use `Array.prototype.some()` to test if any elements in the collection return `true` based on `fn`. Omit the second argument, `fn`, to use `Boolean` as a default."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.367384Z",
     "start_time": "2020-11-30T14:44:13.130Z"
    }
   },
   "outputs": [],
   "source": [
    "const any = (arr, fn = Boolean) => arr.some(fn);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.369331Z",
     "start_time": "2020-11-30T14:44:13.133Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "true\n",
      "true\n"
     ]
    }
   ],
   "source": [
    "console.log(any([0, 1, 2, 0], x => x >= 2));\n",
    "console.log(any([0, 0, 1, 0]));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [compact](https://www.30secondsofcode.org/js/s/compact)\n",
    "JavaScript, Array, Beginner\n",
    "\n",
    "Removes falsy values from an array.\n",
    "\n",
    "Use `Array.prototype.filter()` to filter out falsy values (`false`, `null`, `0`, `\"\"`, `undefined`, and `NaN`)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.378148Z",
     "start_time": "2020-11-30T14:44:13.137Z"
    }
   },
   "outputs": [],
   "source": [
    "const compact = arr => arr.filter(Boolean);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.378583Z",
     "start_time": "2020-11-30T14:44:13.141Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 1, 2, 3, 'a', 's', 34 ]\n"
     ]
    }
   ],
   "source": [
    "console.log(compact([0, 1, false, 2, '', 3, 'a', 'e' * 23, NaN, 's', 34]));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [everyNth]()\n",
    "JavaScript, Array, Beginner\n",
    "\n",
    "Returns every nth element in an array.\n",
    "\n",
    "Use `Array.prototype.filter()` to create a new array that contains every nth element of a given array.\n",
    "\n",
    "---\n",
    "返回奇数index的值\n",
    "\n",
    "---\n",
    "[**`==`和`===`区别**](https://www.cnblogs.com/nelson-hu/p/7922731.html)\n",
    "\n",
    "<details><summary>内容折叠</summary>\n",
    "\n",
    "**双等号 `==` :**\n",
    "\n",
    "　　（1）如果两个值类型相同，再进行三个等号(===)的比较\n",
    "\n",
    "　　（2）如果两个值类型不同，也有可能相等，需根据以下规则进行类型转换在比较：\n",
    "\n",
    "　　　　1）如果一个是null，一个是undefined，那么相等\n",
    "\n",
    "　　　　2）如果一个是字符串，一个是数值，把字符串转换成数值之后再进行比较\n",
    "\n",
    "　　\n",
    "\n",
    "**三等号 `===` :**\n",
    "\n",
    "　　（1）如果类型不同，就一定不相等\n",
    "\n",
    "　　（2）如果两个都是数值，并且是同一个值，那么相等；如果其中至少一个是NaN，那么不相等。（判断一个值是否是NaN，只能使用isNaN( ) 来判断）\n",
    "\n",
    "　　（3）如果两个都是字符串，每个位置的字符都一样，那么相等，否则不相等。\n",
    "\n",
    "　　（4）如果两个值都是true，或是false，那么相等\n",
    "\n",
    "　　（5）如果两个值都引用同一个对象或是函数，那么相等，否则不相等\n",
    "\n",
    "　　（6）如果两个值都是null，或是undefined，那么相等\n",
    "</details>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.393488Z",
     "start_time": "2020-11-30T14:44:13.146Z"
    }
   },
   "outputs": [],
   "source": [
    "const everyNth = (arr, nth) => arr.filter((e, i) => i % nth === nth - 1);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.393921Z",
     "start_time": "2020-11-30T14:44:13.151Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 1, 3, 5 ]\n"
     ]
    }
   ],
   "source": [
    "console.log(everyNth([0, 1, 7, 3, 4, 5, 6], 2));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [filterNonUnique](https://www.30secondsofcode.org/js/s/filter-non-unique)\n",
    "JavaScript, Array, Beginner\n",
    "\n",
    "Filters out the non-unique values in an array.\n",
    "\n",
    "Use `Array.prototype.filter()` for an array containing only the unique values.\n",
    "\n",
    "---\n",
    "返回数组中值唯一的元素"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.395072Z",
     "start_time": "2020-11-30T14:44:13.156Z"
    }
   },
   "outputs": [],
   "source": [
    "const filterNonUnique = arr => arr.filter(i => arr.indexOf(i) === arr.lastIndexOf(i));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.395465Z",
     "start_time": "2020-11-30T14:44:13.160Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 1, 3, 5 ]\n"
     ]
    }
   ],
   "source": [
    "console.log(filterNonUnique([1, 2, 2, 3, 4, 4, 5]));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [uniqueElements](https://www.30secondsofcode.org/js/s/unique-elements)\n",
    "JavaScript, Array, Beginner\n",
    "\n",
    "Returns all unique values in an array.\n",
    "\n",
    "Create a `Set` from the given array to discard duplicated values, then use the spread operator (`...`) to convert it back to an array."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.397826Z",
     "start_time": "2020-11-30T14:44:13.163Z"
    }
   },
   "outputs": [],
   "source": [
    "const uniqueElements = arr => [...new Set(arr)];"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.414632Z",
     "start_time": "2020-11-30T14:44:13.167Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 1, 2, 3, 4, 5 ]\n"
     ]
    }
   ],
   "source": [
    "console.log(uniqueElements([1, 2, 2, 3, 4, 4, 5]));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [findLast](https://www.30secondsofcode.org/js/s/find-last)\n",
    "JavaScript, Array, Beginner\n",
    "\n",
    "Returns the last element for which the provided function returns a truthy value.\n",
    "\n",
    "Use `Array.prototype.filter()` to remove elements for which `fn` returns falsy values, `Array.prototype.pop()` to get the last one.\n",
    "\n",
    "---\n",
    "返回最后一个满足条件的值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.415773Z",
     "start_time": "2020-11-30T14:44:13.171Z"
    }
   },
   "outputs": [],
   "source": [
    "const findLast = (arr, fn) => arr.filter(fn).pop();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.416214Z",
     "start_time": "2020-11-30T14:44:13.174Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3\n"
     ]
    }
   ],
   "source": [
    "console.log(findLast([1, 2, 3, 4], n => n % 2 === 1));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [findLastIndex](https://www.30secondsofcode.org/js/s/find-last-index)\n",
    "JavaScript, Array, Function, Intermediate\n",
    "\n",
    "Returns the index of the last element for which the provided function returns a truthy value.\n",
    "\n",
    "Use `Array.prototype.map()` to map each element to an array with its index and value. Use `Array.prototype.filter()` to remove elements for which `fn` returns falsy values, `Array.prototype.pop()` to get the last one. `-1` is the default value when not found."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.416628Z",
     "start_time": "2020-11-30T14:44:13.181Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Function: findLastIndex]"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "findLastIndex = (arr, fn) =>\n",
    "  (arr\n",
    "    .map((val, i) => [i, val])//调换key,value生成map\n",
    "    .filter(([i, val]) => fn(val, i, arr))//有无 i, arr都可以\n",
    "    .pop() || [-1])[0];//pop() 方法用于删除数组的最后一个元素并返回删除的元素。[0]表示取key,[1]表示取value"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.424824Z",
     "start_time": "2020-11-30T14:44:13.185Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2\n",
      "-1\n"
     ]
    }
   ],
   "source": [
    "console.log(findLastIndex([1, 2, 3, 4], n => n % 2 === 1));\n",
    "console.log(findLastIndex([1, 2, 3, 4], n => n === 5));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.425990Z",
     "start_time": "2020-11-30T14:44:13.190Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2\n"
     ]
    }
   ],
   "source": [
    "//test\n",
    "function test(arr){\n",
    "    new_arr = arr.map((val , i) => [i, val])\n",
    "    .filter(([i, val]) => val === 1)//有无 i, arr都可以\n",
    "    .pop()[0];\n",
    "    console.log(new_arr);\n",
    "}\n",
    "test([2,4,1]);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## head & last\n",
    "JavaScript, Array, Beginner\n",
    "\n",
    "Returns the head of a list.\n",
    "\n",
    "Check if `arr` is truthy and has a `length` property, use `arr[0]` if possible to return the first element, otherwise return `undefined`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.426383Z",
     "start_time": "2020-11-30T14:44:13.195Z"
    }
   },
   "outputs": [],
   "source": [
    "//head\n",
    "const head = arr => (arr && arr.length ? arr[0] : undefined);\n",
    "\n",
    "//last\n",
    "const last = arr => (arr && arr.length ? arr[arr.length - 1] : undefined);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.453366Z",
     "start_time": "2020-11-30T14:44:13.199Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "undefined\n",
      "undefined\n",
      "undefined\n",
      "3\n",
      "undefined\n",
      "undefined\n",
      "undefined\n"
     ]
    }
   ],
   "source": [
    "//head\n",
    "console.log(head([1, 2, 3]));\n",
    "console.log(head([]));\n",
    "console.log(head(null));\n",
    "console.log(head(undefined));\n",
    "\n",
    "//last\n",
    "console.log(last([1, 2, 3]));\n",
    "console.log(last([]));\n",
    "console.log(last(null));\n",
    "console.log(last(undefined));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [includesAll](https://www.30secondsofcode.org/js/s/includes-all) & includesAny\n",
    "JavaScript, Array, Beginner\n",
    "\n",
    "Returns `true` if all the elements in `values` are included in `arr`, `false` otherwise.\n",
    "\n",
    "Use `Array.prototype.every()` and `Array.prototype.includes()` to check if all elements of `values` are included in `arr`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.454575Z",
     "start_time": "2020-11-30T14:44:13.204Z"
    }
   },
   "outputs": [],
   "source": [
    "//every\n",
    "const includesAll = (arr, values) => values.every(v => arr.includes(v));\n",
    "\n",
    "//some\n",
    "const includesAny = (arr, values) => values.some(v => arr.includes(v));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.454995Z",
     "start_time": "2020-11-30T14:44:13.207Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "true\n",
      "false\n",
      "true\n",
      "false\n"
     ]
    }
   ],
   "source": [
    "//includeAll\n",
    "console.log(includesAll([1, 2, 3, 4], [1, 4]));\n",
    "console.log(includesAll([1, 2, 3, 4], [1, 5]));\n",
    "\n",
    "//includeAny\n",
    "console.log(includesAny([1, 2, 3, 4], [2, 9]));\n",
    "console.log(includesAny([1, 2, 3, 4], [8, 9]));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [without](https://www.30secondsofcode.org/js/s/without)\n",
    "JavaScript, Array, Beginner\n",
    "\n",
    "Filters out the elements of an array, that have one of the specified values.\n",
    "\n",
    "Use `Array.prototype.filter()` to create an array excluding(using `!Array.includes()`) all given values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.464408Z",
     "start_time": "2020-11-30T14:44:13.212Z"
    }
   },
   "outputs": [],
   "source": [
    "const without = (arr, ...args) => arr.filter(v => !args.includes(v));\n",
    "const without_ = (arr, args) => arr.filter(v => !args.includes(v));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.464841Z",
     "start_time": "2020-11-30T14:44:13.216Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 3 ]\n",
      "[ 3 ]\n"
     ]
    }
   ],
   "source": [
    "console.log(without([2, 1, 2, 3], 1, 2));\n",
    "console.log(without_([2, 1, 2, 3], [1, 2]));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [difference](https://www.30secondsofcode.org/js/s/difference) & !difference\n",
    "JavaScript, Array, Math, Beginner\n",
    "\n",
    "Returns the difference between two arrays.\n",
    "\n",
    "Create a `Set` from `b`, then use `Array.prototype.filter()` on `a` to only keep values not contained in `b`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.465212Z",
     "start_time": "2020-11-30T14:44:13.220Z"
    }
   },
   "outputs": [],
   "source": [
    "const difference = (a, b) => {\n",
    "    const s = new Set(b);\n",
    "    return a.filter(x => !s.has(x));\n",
    "};"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.484101Z",
     "start_time": "2020-11-30T14:44:13.223Z"
    }
   },
   "outputs": [],
   "source": [
    "const both = (a, b) => {\n",
    "    return a.filter(x => b.includes(x));\n",
    "};"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.489061Z",
     "start_time": "2020-11-30T14:44:13.227Z"
    },
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 3 ]\n",
      "[ 1, 2 ]\n"
     ]
    }
   ],
   "source": [
    "console.log(difference([1, 2, 3], [1, 2, 4]));\n",
    "console.log(both([1, 2, 3], [1, 2, 4]));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [maxN](https://www.30secondsofcode.org/js/s/max-n)  & minN\n",
    "JavaScript, Array, Math, Beginner\n",
    "\n",
    "Returns the `n` maximum elements from the provided array. If `n` is greater than or equal to the provided array's length, then return the original array (sorted in descending order).\n",
    "\n",
    "Use `Array.prototype.sort()` combined with the spread operator (`...`) to create a shallow clone of the array and sort it in descending order. Use `Array.prototype.slice()` to get the specified number of elements. Omit the second argument, `n`, to get a one-element array.\n",
    "\n",
    "补充：[JavaScript中sort()对数组数字项函数function（a,b）返回值为a-b即为升序排列的细解](https://blog.csdn.net/weimob258616/article/details/89737057)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.490264Z",
     "start_time": "2020-11-30T14:44:13.230Z"
    }
   },
   "outputs": [],
   "source": [
    "// maxN\n",
    "const maxN = (arr, n = 1) => [...arr].sort((a, b) => b - a).slice(0, n);\n",
    "\n",
    "//minN\n",
    "const minN = (arr, n = 1) => [...arr].sort((a, b) => a - b).slice(0, n);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.490712Z",
     "start_time": "2020-11-30T14:44:13.234Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 25 ]\n",
      "[ 63, 11 ]\n",
      "[ 4 ]\n",
      "[ 2, 8 ]\n"
     ]
    }
   ],
   "source": [
    "//maxN\n",
    "console.log(maxN([4, 25, 8, 24]));\n",
    "console.log(maxN([11,2, 63, 8], 2));\n",
    "\n",
    "//minN\n",
    "console.log(minN([4, 25, 8, 24]));\n",
    "console.log(minN([11,2, 63, 8], 2));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [none](https://www.30secondsofcode.org/js/s/none)\n",
    "JavaScript, Array, Function, Beginner\n",
    "\n",
    "Returns `true` if the provided predicate function returns `false` for all elements in a collection, `false` otherwise.\n",
    "\n",
    "Use `Array.prototype.some()` to test if any elements in the collection return `true` based on `fn`. Omit the second argument, `fn`, to use `Boolean` as a default."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.491120Z",
     "start_time": "2020-11-30T14:44:13.239Z"
    }
   },
   "outputs": [],
   "source": [
    "const none = (arr, fn = Boolean) => !arr.some(fn);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.491566Z",
     "start_time": "2020-11-30T14:44:13.243Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "true\n",
      "true\n",
      "[Function: Boolean]\n"
     ]
    }
   ],
   "source": [
    "console.log(none([0, 1, 3, 0], x => x == 2));\n",
    "console.log(none([0, 0, 0]));\n",
    "\n",
    "b = (Boolean);\n",
    "console.log(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [nthElement](https://www.30secondsofcode.org/js/s/nth-element)\n",
    "JavaScript, Array, Beginner\n",
    "\n",
    "Returns the nth element of an array.\n",
    "\n",
    "Use `Array.prototype.slice()` to get an array containing the nth element at the first place. If the index is out of bounds, return `undefined`. Omit the second argument, `n`, to get the first element of the array."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.507237Z",
     "start_time": "2020-11-30T14:44:13.248Z"
    }
   },
   "outputs": [],
   "source": [
    "const nthElement = (arr, n = 0) => (n === -1 ? arr.slice(n) : arr.slice(n, n + 1))[0];"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.507704Z",
     "start_time": "2020-11-30T14:44:13.251Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "b\n",
      "a\n"
     ]
    }
   ],
   "source": [
    "console.log(nthElement(['a', 'b', 'c'], 1));\n",
    "console.log(nthElement(['a', 'b', 'b'], -3));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.508141Z",
     "start_time": "2020-11-30T14:44:13.255Z"
    },
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 'o', 'u' ]\n"
     ]
    }
   ],
   "source": [
    "console.log(['a','n','l','z','o','u'].slice(-2));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [offset](https://www.30secondsofcode.org/js/s/offset)\n",
    "JavaScript, Array, Beginner\n",
    "\n",
    "Moves the specified amount of elements to the end of the array.\n",
    "\n",
    "Use `Array.prototype.slice()` twice to get the elements after the specified index and the elements before that. Use the spread operator(`...`) to combine the two into one array. If `offset` is negative, the elements will be moved from end to start."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.508554Z",
     "start_time": "2020-11-30T14:44:13.258Z"
    }
   },
   "outputs": [],
   "source": [
    "const offset = (arr, offset) => [...arr.slice(offset), ...arr.slice(0, offset)];"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.514438Z",
     "start_time": "2020-11-30T14:44:13.263Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 3, 4, 5, 1, 2 ]\n",
      "[ 4, 5, 1, 2, 3 ]\n"
     ]
    }
   ],
   "source": [
    "console.log(offset([1, 2, 3, 4, 5], 2));\n",
    "console.log(offset([1, 2, 3, 4, 5], -2));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [reject](https://www.30secondsofcode.org/js/s/reject)\n",
    "JavaScript, Array, Beginner\n",
    "\n",
    "Filters an array's values based on a predicate function, returning only values for which the predicate function returns `false`.\n",
    "\n",
    "Use `Array.prototype.filter()` in combination with the predicate function, `pred`, to return only the values for which `pred()` returns `false`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.514873Z",
     "start_time": "2020-11-30T14:44:13.267Z"
    }
   },
   "outputs": [],
   "source": [
    "const reject = (array, pred) => array.filter((...args) => pred(...args));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.515296Z",
     "start_time": "2020-11-30T14:44:13.271Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 2, 4 ]\n",
      "[ 'Apple', 'Banana' ]\n"
     ]
    }
   ],
   "source": [
    "console.log(reject([1, 2, 3, 4, 5], x => x % 2 === 0));\n",
    "console.log(reject(['Apple', 'Pear', 'Kiwi', 'Banana'], word => word.length > 4));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [sample](https://www.30secondsofcode.org/js/s/sample)\n",
    "JavaScript, Array, Random, Beginner\n",
    "\n",
    "Returns a random element from an array.\n",
    "\n",
    "Use `Math.random()` to generate a random number, multiply it by `length` and round it off to the nearest whole number using `Math.floor()`. This method also works with strings."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.520439Z",
     "start_time": "2020-11-30T14:44:13.276Z"
    }
   },
   "outputs": [],
   "source": [
    "//Math.random() * arr.length所得到的的是[0,arr.lenght)之间的随机数，每次刷新都不同\n",
    "const sample = arr => arr[Math.floor(Math.random() * arr.length)];"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.525242Z",
     "start_time": "2020-11-30T14:44:13.280Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "9\n",
      "0.546161332243509\n"
     ]
    }
   ],
   "source": [
    "console.log(sample([3, 7, 9, 11]));\n",
    "\n",
    "//所得到的的值是0-1之间的 随机数，每次刷新都不同\n",
    "console.log(Math.random());"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## tail"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.533286Z",
     "start_time": "2020-11-30T14:44:13.285Z"
    }
   },
   "outputs": [],
   "source": [
    "const tail = arr => (arr.length > 1 ? arr.slice(1) : arr);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.535028Z",
     "start_time": "2020-11-30T14:44:13.289Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 2, 3 ]\n",
      "[ 4 ]\n"
     ]
    }
   ],
   "source": [
    "console.log(tail([1,2,3]));\n",
    "console.log(tail([4]));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## take"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.543160Z",
     "start_time": "2020-11-30T14:44:13.293Z"
    }
   },
   "outputs": [],
   "source": [
    "const take = (arr, n = 1) => arr.slice(0, n);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.543670Z",
     "start_time": "2020-11-30T14:44:13.297Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 1, 2, 3 ]\n",
      "[]\n"
     ]
    }
   ],
   "source": [
    "console.log(take([1,2,3],5));\n",
    "console.log(take([1,2,3],0));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [similarity](https://www.30secondsofcode.org/js/s/similarity)（交集）\n",
    "JavaScript, Array, Math, Beginner\n",
    "\n",
    "Returns an array of elements that appear in both arrays.\n",
    "\n",
    "Use `Array.prototype.filter()` to remove values that are not part of `values`, determined using `Array.prototype.includes()`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.544064Z",
     "start_time": "2020-11-30T14:44:13.301Z"
    }
   },
   "outputs": [],
   "source": [
    "const similarity = (arr1, arr2) => arr1.filter(v => arr2.includes(v));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.560073Z",
     "start_time": "2020-11-30T14:44:13.305Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 1, 2 ]\n"
     ]
    }
   ],
   "source": [
    "console.log(similarity([1,2,3], [1,2,4]));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## union（并集）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.560534Z",
     "start_time": "2020-11-30T14:44:13.312Z"
    }
   },
   "outputs": [],
   "source": [
    "const union = (a, b) => Array.from(new Set([...a, ...b]));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.565943Z",
     "start_time": "2020-11-30T14:44:13.316Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 1, 2, 3, 4 ]\n"
     ]
    }
   ],
   "source": [
    "console.log(union([1,2,3],[4,1,2]));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.566367Z",
     "start_time": "2020-11-30T14:44:13.321Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 1, 2, 3, 2, 3, 4 ]\n"
     ]
    }
   ],
   "source": [
    "//合集\n",
    "a = [1,2,3];\n",
    "b = [2,3,4];\n",
    "console.log([...a,...b]);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 补充： [`...` ES6扩展运算符](http://www.fly63.com/article/detial/2516)\n",
    "\n",
    "拓展运算符，是es6一个很好的特性，它们可以通过减少赋值语句的使用，或者减少通过下标访问数组或对象的方式，使代码更加简洁优雅，可读性更佳。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 在函数调用时使用拓展运算符\n",
    "以前如果我们想将数组元素迭代为函数参数使用，一般使用Function.prototype.apply的方式。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.571064Z",
     "start_time": "2020-11-30T14:44:13.325Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "012\n"
     ]
    }
   ],
   "source": [
    "function myFunction(x, y, z) { \n",
    "  console.log(x+\"\"+y+\"\"+z);\n",
    "} \n",
    "var args = [0, 1, 2]; \n",
    "myFunction.apply(null, args);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-31T07:07:26.778234Z",
     "start_time": "2020-08-31T07:07:25.030Z"
    }
   },
   "source": [
    "有了展开语法，我们可以这样写。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.573820Z",
     "start_time": "2020-11-30T14:44:13.329Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "012\n"
     ]
    }
   ],
   "source": [
    "function myFunction(x, y, z) { \n",
    "  console.log(x+\"\"+y+\"\"+z); \n",
    "} \n",
    "\n",
    "var args = [0, 1, 2]; \n",
    "myFunction(...args);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**提示**: ...arr返回的并不是一个数组，而是各个数组的值。只有[...arr]才是一个数组，所以...arr可以用来对方法进行传值"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 数组和对象的拷贝"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.590100Z",
     "start_time": "2020-11-30T14:44:13.333Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "false\n",
      "true\n",
      "[ 1, 2, 3, 4 ]\n",
      "[ 1, 2, 3, 4 ]\n",
      "[ 1, 2, 3, 4 ]\n"
     ]
    }
   ],
   "source": [
    "var arr1 = [1,2,3];\n",
    "var arr2 = [...arr1];  //拷贝\n",
    "var arr3 = arr1;  //对象引用\n",
    "\n",
    "arr2.push(4);\n",
    "arr1.push(4);\n",
    "\n",
    "console.log(arr1 === arr2);\n",
    "console.log(arr1 === arr3);\n",
    "console.log(arr1);\n",
    "console.log(arr2);\n",
    "console.log(arr3);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对象也是一样，也可以使用拓展运算符"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.590574Z",
     "start_time": "2020-11-30T14:44:13.336Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{ a: 1, b: 2 }\n",
      "false\n"
     ]
    }
   ],
   "source": [
    "var obj1 = {\n",
    "    a:1,\n",
    "    b:2\n",
    "};\n",
    "var obj2 = {...obj1};\n",
    "console.log(obj2); //{ a:1, b:2}\n",
    "console.log(obj1 === obj2);// false"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**提示**: 在这里你会发现，这是一个深拷贝，其实不然，实际上, 展开语法和 Object.assign() 行为一致, 执行的都是浅拷贝(只遍历一层)。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 构造字面量数组\n",
    "没有展开语法的时候，只能组合使用 push, splice, concat 等方法，来将已有数组元素变成新数组的一部分。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.601573Z",
     "start_time": "2020-11-30T14:44:13.339Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 4, 5, 1, 2, 3 ]\n"
     ]
    }
   ],
   "source": [
    "var arr1 = [1,2,3];\n",
    "var arr2 = [4,5,...arr1];\n",
    "console.log(arr2);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "代替Array.concat 函数\n",
    "\n",
    "concat() 方法用于连接两个或多个数组。\n",
    "\n",
    "该方法不会改变现有的数组，而仅仅会返回被连接数组的一个副本。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.602104Z",
     "start_time": "2020-11-30T14:44:13.343Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 1, 2, 3, 4, 5, 6 ]\n"
     ]
    }
   ],
   "source": [
    "var arr1 = [1,2,3];\n",
    "var arr2 = [4,5,6];\n",
    "var demo = [...arr1,...arr2];\n",
    "console.log(demo);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "代替Array.unshift 方法\n",
    "\n",
    "unshift() 方法可向数组的开头添加一个或更多元素，并返回新的长度。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.602558Z",
     "start_time": "2020-11-30T14:44:13.347Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "6\n"
     ]
    }
   ],
   "source": [
    "var arr1 = [1,2,3];\n",
    "var arr2 = [4,5,6];\n",
    "arr1 = [...arr2,...arr1];\n",
    "console.log(arr1.length);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 字符串转数组"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.606465Z",
     "start_time": "2020-11-30T14:44:13.352Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 'h', 'e', 'l', 'l', 'o' ]\n"
     ]
    }
   ],
   "source": [
    "var demo = \"hello\"\n",
    "var str = [...demo];\n",
    "console.log(str);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 剩余语法（剩余参数，rest运算符）\n",
    "剩余语法(Rest syntax) 看起来和展开语法完全相同，不同点在于, 剩余参数用于解构数组和对象。从某种意义上说，剩余语法与展开语法是相反的：展开语法将数组展开为其中的各个元素，而剩余语法则是将多个元素收集起来并“凝聚”为单个元素。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 主要用于不定参数，所以es6开始不再使用arguments对象\n",
    "\n",
    "Javascrip中每个函数都会有一个Arguments对象实例arguments，它引用着函数的实参，可以用数组下标的方式\"[]\"引用arguments的元素。arguments.length为函数实参个数，arguments.callee引用函数自身。\n",
    "\n",
    "**特性：**\n",
    "1. arguments对象和Function是分不开的。\n",
    "2. 因为arguments这个对象不能显式创建。\n",
    "3. arguments对象只有函数开始时才可用。\n",
    "\n",
    "**使用方法：**\n",
    "虽然arguments对象并不是一个数组，但是访问单个参数的方式与访问数组元素的方式相同\n",
    "\n",
    "例如：\n",
    "\n",
    "`arguments[0]`,`arguments[1]`,...`arguments[n]`； \n",
    "\n",
    "在js中 不需要明确指出参数名，就能访问它们：\n",
    "```js\n",
    "function test() {\n",
    "        var s = \"\";\n",
    "        for (var i = 0; i < arguments.length; i++) {\n",
    "            alert(arguments[i]);\n",
    "            s += arguments[i] + \",\";\n",
    "        }\n",
    "        return s;\n",
    "}\n",
    "test(\"name\", \"age\");// name,age\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.620278Z",
     "start_time": "2020-11-30T14:44:13.356Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n"
     ]
    }
   ],
   "source": [
    "var demo = function (...arg){\n",
    "    for (let item of arg){\n",
    "        console.log(item);\n",
    "    }\n",
    "}\n",
    "demo(1,2,3);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.620702Z",
     "start_time": "2020-11-30T14:44:13.358Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "[ 2, 3, 4 ]\n"
     ]
    }
   ],
   "source": [
    "var demo = function (a,...arg){\n",
    "    console.log(a);\n",
    "    console.log(arg);\n",
    "}\n",
    "demo(1,2,3,4);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 配合解构一起使用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.621074Z",
     "start_time": "2020-11-30T14:44:13.361Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "[ 2, 3, 4 ]\n"
     ]
    }
   ],
   "source": [
    "var [a,...rest] = [1,2,3,4];\n",
    "\n",
    "console.log(a);\n",
    "console.log(rest);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.631678Z",
     "start_time": "2020-11-30T14:44:13.364Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "{ b: 2, c: 3 }\n"
     ]
    }
   ],
   "source": [
    "var obj = {\n",
    "    a:1,\n",
    "    b:2,\n",
    "    c:3\n",
    "}\n",
    "var {a,...demo} = obj;\n",
    "\n",
    "console.log(a);\n",
    "console.log(demo);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.632095Z",
     "start_time": "2020-11-30T14:44:13.367Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "NaN\n",
      "1\n",
      "6\n",
      "1\n",
      "6\n"
     ]
    }
   ],
   "source": [
    "function f(...[a, b, c]) {\n",
    "  console.log(a);\n",
    "  return a + b + c;\n",
    "}\n",
    "\n",
    "console.log(f(1))\n",
    "console.log(f(1, 2, 3))\n",
    "console.log(f(1, 2, 3, 4))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 小结：\n",
    "等号表达式是典型的赋值形式，函数传参和for循环的变量都是特殊形式的赋值。解构的原理是赋值的两边具有相同的结构，就可以正确取出数组或对象里面的元素或属性值，省略了使用下标逐个赋值的麻烦。对于三个点号，三点放在形参或者等号左边为rest运算符; 放在实参或者等号右边为spread运算符，或者说，放在被赋值一方为rest运算符，放在赋值一方为扩展运算符。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 补充：ES6中的解构赋值\n",
    "什么是解构赋值？\n",
    "\n",
    "解构赋值允许你使用类似数组或对象字面量的语法将数组和对象的属性值赋给一系列变量。这个语法非常简洁，而且比传统的属性访问更加清晰。\n",
    "\n",
    "[关于JS解构的5种有趣用法](https://www.jb51.net/article/169392.htm)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 交换变量\n",
    "常见的交互两个变量值的方法都需要借助一个额外的变量，看一个简单的例子："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.642188Z",
     "start_time": "2020-11-30T14:44:13.371Z"
    }
   },
   "outputs": [],
   "source": [
    "let a = 1;\n",
    "let b = 2;\n",
    "let temp;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.642694Z",
     "start_time": "2020-11-30T14:44:13.375Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2\n",
      "1\n"
     ]
    }
   ],
   "source": [
    "temp = a;\n",
    "a = b;\n",
    "b = temp;\n",
    "console.log(a);\n",
    "console.log(b);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-31T07:50:23.771060Z",
     "start_time": "2020-08-31T07:50:22.069Z"
    }
   },
   "source": [
    "temp是一个临时变量，在例子中存储了变量a的值，b的值赋给了a，最后把temp的值赋给了b。\n",
    "解构运算使得交换变量的值变得非常简单，不需要借助第三个临时变量："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.643937Z",
     "start_time": "2020-11-30T14:44:13.379Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n"
     ]
    }
   ],
   "source": [
    "[a, b] = [b, a];\n",
    "console.log(a);\n",
    "console.log(b);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[a, b] = [b, a]是一个解构运算。在等号的右侧，创建了一个数组[b, a]，对应的值为[2, 1]。数组的第一个值2被解构赋值给了a，第二项1被解构赋值给了b。\n",
    "\n",
    "即使这种方式仍然创建了一个临时数组，但是解构赋值对于交换变量的值仍然是非常高效简单的方式。\n",
    "\n",
    "这种方式并没有什么限制。你还可以同时交互更多的变量值，比如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.655532Z",
     "start_time": "2020-11-30T14:44:13.382Z"
    }
   },
   "outputs": [],
   "source": [
    "let zero = 2;\n",
    "let one = 1;\n",
    "let two = 0;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.658092Z",
     "start_time": "2020-11-30T14:44:13.385Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "1\n",
      "2\n"
     ]
    }
   ],
   "source": [
    "[zero, one, two] = [two, one, zero];\n",
    "console.log(zero);\n",
    "console.log(one);\n",
    "console.log(two);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "你可以交换任意数量的变量值，只是两个变量值的交换的情况更加常见。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 访问数组\n",
    "有一个数组，这个数组有可能是空的。有一种需求是访问任意位置数组元素，如果这个位置为空，则返回一个默认值。\n",
    "\n",
    "通常情况下有的人可能会使用数组的length属性做判断："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.658544Z",
     "start_time": "2020-11-30T14:44:13.388Z"
    }
   },
   "outputs": [],
   "source": [
    "const colors = [];\n",
    "let firstColor = \"white\";"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.659019Z",
     "start_time": "2020-11-30T14:44:13.391Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "white\n"
     ]
    }
   ],
   "source": [
    "if (colors.length > 0) {\n",
    "  firstColor = colors[0];\n",
    "}\n",
    "console.log(firstColor);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "幸运的是，数组解构可以更快捷高效的实现相同的效果："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.668792Z",
     "start_time": "2020-11-30T14:44:13.394Z"
    }
   },
   "outputs": [],
   "source": [
    "const colors_2 = [];\n",
    "const [firstColor_2 = \"white\"] = colors_2;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.669981Z",
     "start_time": "2020-11-30T14:44:13.397Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "white\n"
     ]
    }
   ],
   "source": [
    "console.log(firstColor_2);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`const [firstColor_ = \"white\"] = colors_;`将colors_数组的第一个元素赋值给了变量firstColor_。如果这个数组的下标为0的位置上没有任何元素（注：为undefined时即认为为空），white将作为默认值赋值给firstColor_。\n",
    "\n",
    "数组解构是非常灵活的，如果你只想访问数组的第二个元素，方法如下所示："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.671172Z",
     "start_time": "2020-11-30T14:44:13.400Z"
    }
   },
   "outputs": [],
   "source": [
    "const colors_3 = [];\n",
    "const [, secondColor_3 = \"black\"] = colors_3;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.684809Z",
     "start_time": "2020-11-30T14:44:13.403Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "black\n"
     ]
    }
   ],
   "source": [
    "console.log(secondColor_3);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在解构表达式的左边写一个逗号：意味着数组的第一个元素被忽略掉。colors数组下标为1的元素被解构赋值给了变量secondColor。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 不可变操作\n",
    "从我开始使用React，到后来的Redux，我被迫开始写一些遵循不可变原则的代码。刚开始的时候确实有点不适应，不过后来我就意识到了这种方式的好处：它使得处理单向数据流更加容易。\n",
    "\n",
    "不可变原则禁止修改对象。幸运的是，解构可以帮助你在遵循不可变原则的同时完成这些操作。\n",
    "\n",
    "将解构与展开运算符（rest operator）结合使用来移除数组的第一个元素："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.695782Z",
     "start_time": "2020-11-30T14:44:13.408Z"
    }
   },
   "outputs": [],
   "source": [
    "const numbers = [1,2,3];\n",
    "const [, ...fooNumbers] = numbers;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.697038Z",
     "start_time": "2020-11-30T14:44:13.411Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 2, 3 ]\n",
      "[ 1, 2, 3 ]\n"
     ]
    }
   ],
   "source": [
    "console.log(fooNumbers);\n",
    "console.log(numbers);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这个解构操作`[, ...fooNumbers] = numbers`创建了一个新的数组fooNumbers，这个数组包含numbers除了第一个元素外的其余元素。\n",
    "\n",
    "numbers数组并没有被改变，这种方式遵循了不可变原则。\n",
    "\n",
    "除此之外，你也可以在遵循不可变原则的同时使用同样的方法来删除一个对象的属性。如下所示，删除big对象的foo属性："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.697487Z",
     "start_time": "2020-11-30T14:44:13.414Z"
    }
   },
   "outputs": [],
   "source": [
    "const big = {\n",
    "  foo: \"value foo\",\n",
    "  bar: \"value bar\",\n",
    "}\n",
    "const { foo, ...small } = big;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.697904Z",
     "start_time": "2020-11-30T14:44:13.417Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{ bar: 'value bar' }\n",
      "{ foo: 'value foo', bar: 'value bar' }\n"
     ]
    }
   ],
   "source": [
    "console.log(small);\n",
    "console.log(big);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上述方法将解构与对象展开运算符结合起来使用，创建了一个新的对象small，这个新对象包含big对象除了foo属性之外的所有属性。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 解构可迭代的值\n",
    "在前面几部分内容中，都是解构的数组。实际上解构运算是可以用于所有的可迭代对象的。\n",
    "\n",
    "许多原生的基础类型和对象都是可迭代的，例如数组，类数组，字符串，set集合和map集合。\n",
    "\n",
    "例如，你可以把字符串解构成单个字符："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.698385Z",
     "start_time": "2020-11-30T14:44:13.420Z"
    }
   },
   "outputs": [
    {
     "ename": "SyntaxError",
     "evalue": "Identifier 'str' has already been declared",
     "output_type": "error",
     "traceback": [
      "evalmachine.<anonymous>:1",
      "const str = \"cheese\";",
      "^",
      "",
      "SyntaxError: Identifier 'str' has already been declared",
      "    at evalmachine.<anonymous>:1:1",
      "    at Script.runInThisContext (vm.js:131:20)",
      "    at Object.runInThisContext (vm.js:297:38)",
      "    at run ([eval]:1054:15)",
      "    at onRunRequest ([eval]:888:18)",
      "    at onMessage ([eval]:848:13)",
      "    at process.emit (events.js:315:20)",
      "    at emit (internal/child_process.js:881:12)",
      "    at processTicksAndRejections (internal/process/task_queues.js:85:21)"
     ]
    }
   ],
   "source": [
    "const str = \"cheese\";\n",
    "const [firstChar = \"\"] = str;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.698854Z",
     "start_time": "2020-11-30T14:44:13.423Z"
    }
   },
   "outputs": [
    {
     "ename": "ReferenceError",
     "evalue": "firstChar is not defined",
     "output_type": "error",
     "traceback": [
      "evalmachine.<anonymous>:1",
      "console.log(firstChar);",
      "            ^",
      "",
      "ReferenceError: firstChar is not defined",
      "    at evalmachine.<anonymous>:1:13",
      "    at Script.runInThisContext (vm.js:131:20)",
      "    at Object.runInThisContext (vm.js:297:38)",
      "    at run ([eval]:1054:15)",
      "    at onRunRequest ([eval]:888:18)",
      "    at onMessage ([eval]:848:13)",
      "    at process.emit (events.js:315:20)",
      "    at emit (internal/child_process.js:881:12)",
      "    at processTicksAndRejections (internal/process/task_queues.js:85:21)"
     ]
    }
   ],
   "source": [
    "console.log(firstChar);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当然解构不仅仅限于原生可迭代的那几种类型。解构可以被用于所有实现了迭代接口（iterable protocol）的对象。如下所示，movies包含一个movie对象列表。我们想要解构movies对象的时候，可以获取到电影的title这个字符串。实现这个操作首先需要自定义一个迭代器："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.711861Z",
     "start_time": "2020-11-30T14:44:13.427Z"
    }
   },
   "outputs": [],
   "source": [
    "const movies = {\n",
    "  list: [\n",
    "    { title: \"Heat\" },\n",
    "    { title: \"Interstellar\" },\n",
    "  ],\n",
    "  [Symbol.iterator]() {\n",
    "    let index = 0;\n",
    "    return {\n",
    "      next: () => {\n",
    "        if (index < this.list.length) {\n",
    "          const value = this.list[index++].title;\n",
    "          return { value, done: false };\n",
    "        }\n",
    "        return { done: true }\n",
    "      }\n",
    "    }\n",
    "  }\n",
    "}\n",
    "\n",
    "const [firstMovieTitle] = movies;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.712351Z",
     "start_time": "2020-11-30T14:44:13.430Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Heat\n"
     ]
    }
   ],
   "source": [
    "console.log(firstMovieTitle);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "movies对象通过定义`Symbol.iterator`方法实现了一个迭代器。这个迭代器可以迭代所有电影的title属性。\n",
    "\n",
    "我们在movies对象上遵循了迭代接口实现，从而实现了通过解构movies来获取到标题，比如我们获取第一个电影的标题：`const [firstMovieTitle] = movies;` 。\n",
    "\n",
    "解构用法的上限就是没有上限。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 解构动态属性\n",
    "在我的经验中，解构一个对象的属性要远比解构一个数组的情况更多。\n",
    "\n",
    "解构对象看起来非常的简单："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.717563Z",
     "start_time": "2020-11-30T14:44:13.433Z"
    }
   },
   "outputs": [],
   "source": [
    "const movie = { title: \"Heat\" };\n",
    "const { title } = movie;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.718020Z",
     "start_time": "2020-11-30T14:44:13.436Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Heat\n"
     ]
    }
   ],
   "source": [
    "console.log(title);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`const { title } = movie;`创建了一个变量title，然后把movie.title的值赋值给了这个变量。\n",
    "\n",
    "当我第一次了解到对象解构的时候，有一点令我惊讶的是你并不需要预先知道属性的静态名称。你可以通过动态属性名来解构一个对象。\n",
    "\n",
    "为了了解动态解构的工作原理，我们来写一个打招呼的函数作为例子："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.719234Z",
     "start_time": "2020-11-30T14:44:13.441Z"
    }
   },
   "outputs": [],
   "source": [
    "function greet( obj, nameProp ) {\n",
    "  const { [nameProp]: name=\"Unknow\" } = obj;\n",
    "  return `Hello, ${name}!`;\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.719673Z",
     "start_time": "2020-11-30T14:44:13.444Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello, Batman!\n",
      "Hello, Unknow!\n"
     ]
    }
   ],
   "source": [
    "console.log(greet({ name: \"Batman\" }, \"name\"));\n",
    "console.log(greet( {}, \"name\" ));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "greet()被调用时需要传递两个参数，一个是对象，一个是属性名称。\n",
    "\n",
    "在greet()函数内部，解构表达式`const { [nameProp]: name=\"Unknow\" } = obj;`使用中括号[nameProp]读取动态属性的名称。name变量接收动态属性的值。\n",
    "\n",
    "更好的做法就是你可以指定一个默认的值Unknow以防属性不存在的情况。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 总结\n",
    "解构可以帮助你更方便快捷的访问对象属性和数组元素。\n",
    "\n",
    "除了基本用法之外，数组解构还可以方便的交换变量，访问数组元素，做一些遵循不可变原则的操作。\n",
    "\n",
    "JavaScript提供了更多的可能性，因为你可以通过扩展迭代器实现自定义的解构逻辑。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Intermediate"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [aperture](https://www.30secondsofcode.org/js/s/aperture)\n",
    "JavaScript, Array, Intermediate\n",
    "\n",
    "Returns an array of `n-tuples` of consecutive elements.\n",
    "\n",
    "Use `Array.prototype.slice()` and `Array.prototype.map()` to create an array of appropriate length and populate it with `n-tuples` of consecutive elements from `arr`. If `n` is greater than the length of `arr`, return an empty array.\n",
    "\n",
    "---\n",
    "**定义和用法**\n",
    "- map() 方法返回一个新数组，数组中的元素为原始数组元素调用函数处理后的值。\n",
    "- map() 方法按照原始数组元素顺序依次处理元素。\n",
    "\n",
    "**注意：**\n",
    "- map() 不会对空数组进行检测。\n",
    "- map() 不会改变原始数组。\n",
    "\n",
    "**语法**\n",
    "```js\n",
    "array.map(function(currentValue,index,arr), thisValue)\n",
    "```\n",
    "- function(currentValue, index,arr)\t必须。函数，数组中的每个元素都会执行这个函数\n",
    "    - currentValue\t必须。当前元素的值\n",
    "    - index\t可选。当前元素的索引值\n",
    "    - arr\t可选。当前元素属于的数组对象\n",
    "- thisValue\t可选。对象作为该执行回调时使用，传递给函数，用作 \"this\" 的值。如果省略了 thisValue，或者传入 null、undefined，那么回调函数的 this 为全局对象。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.726343Z",
     "start_time": "2020-11-30T14:44:13.448Z"
    }
   },
   "outputs": [],
   "source": [
    "const aperture = (n, arr) =>\n",
    "  n > arr.length\n",
    "    ? []\n",
    "    : arr.slice(n - 1).map((v, i) => [...arr.slice(i, i + n - 1), v]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.728521Z",
     "start_time": "2020-11-30T14:44:13.451Z"
    },
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ [ 1, 2 ], [ 2, 3 ], [ 3, 4 ] ]\n",
      "[ [ 1, 2, 3 ], [ 2, 3, 4 ] ]\n",
      "[]\n"
     ]
    }
   ],
   "source": [
    "console.log(aperture(2, [1, 2, 3, 4]));\n",
    "console.log(aperture(3, [1, 2, 3, 4]));\n",
    "console.log(aperture(5, [1, 2, 3, 4]));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.750337Z",
     "start_time": "2020-11-30T14:44:13.455Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ [ 1, 2, 3 ], [ 2, 3, 4 ] ]\n"
     ]
    }
   ],
   "source": [
    "n = 3;\n",
    "a = [1, 2, 3, 4]\n",
    "b = a.slice(n - 1).map((v, i) => [...a.slice(i, i + n - 1), v]);\n",
    "console.log(b);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [chunk](https://www.30secondsofcode.org/js/s/chunk)\n",
    "JavaScript, Array, Intermediate\n",
    "\n",
    "Chunks an array into smaller arrays of a specified size.\n",
    "\n",
    "Use `Array.from()` to create a new array, that fits the number of chunks that will be produced. Use `Array.prototype.slice()` to map each element of the new array to a chunk the length of `size`. If the original array can't be split evenly, the final chunk will contain the remaining elements.\n",
    "\n",
    "---\n",
    "`from()` 方法用于通过拥有 length 属性的对象或可迭代的对象来返回一个数组。\n",
    "\n",
    "如果对象是数组返回 true，否则返回 false。\n",
    "\n",
    "**语法**\n",
    "```js\n",
    "Array.from(object, mapFunction, thisValue)\n",
    "```\n",
    "**参数**\n",
    "- object\t必需，要转换为数组的对象。\n",
    "- mapFunction\t可选，数组中每个元素要调用的函数。\n",
    "- thisValue\t可选，映射函数(mapFunction)中的 this 对象。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 90,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.751519Z",
     "start_time": "2020-11-30T14:44:13.458Z"
    }
   },
   "outputs": [],
   "source": [
    "const chunk = (arr, size) =>\n",
    "  Array.from({ length: Math.ceil(arr.length / size) }, (v, i) =>\n",
    "    arr.slice(i * size, i * size + size)\n",
    "  );"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.755184Z",
     "start_time": "2020-11-30T14:44:13.461Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ [ 1, 2, 3 ], [ 4, 5 ] ]\n"
     ]
    }
   ],
   "source": [
    "console.log(chunk([1, 2, 3, 4, 5], 3));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 92,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.755607Z",
     "start_time": "2020-11-30T14:44:13.464Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "undefined\n",
      "undefined\n",
      "undefined\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[ undefined, undefined, undefined ]"
      ]
     },
     "execution_count": 92,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "//v为undefined，v是初始值\n",
    "test = (arr, size) =>\n",
    "  Array.from({ length: Math.ceil(arr.length / size) }, (v, i) =>\n",
    "    console.log(v)\n",
    "//     console.log(i)\n",
    "  );\n",
    "\n",
    "test([1, 2, 3, 4, 5], 2);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [chunkIntoN](https://www.30secondsofcode.org/js/s/chunk-into-n)\n",
    "JavaScript, Array, Intermediate\n",
    "\n",
    "Chunks an array into `n` smaller arrays.\n",
    "\n",
    "Use `Math.ceil()` and `Array.prototype.length` to get the size of each chunk. Use `Array.from()` to create a new array of size `n`. Use `Array.prototype.slice()` to map each element of the new array to a chunk the length of `size`. If the original array can't be split evenly, the final chunk will contain the remaining elements."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 93,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.756065Z",
     "start_time": "2020-11-30T14:44:13.466Z"
    }
   },
   "outputs": [],
   "source": [
    "const chunkIntoN = (arr, n) => {\n",
    "  const size = Math.ceil(arr.length / n);\n",
    "  return Array.from({ length: n }, (v, i) =>\n",
    "    arr.slice(i * size, i * size + size)\n",
    "  );\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 94,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.756486Z",
     "start_time": "2020-11-30T14:44:13.470Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ], [ 7 ] ]\n"
     ]
    }
   ],
   "source": [
    "console.log(chunkIntoN([1, 2, 3, 4, 5, 6, 7], 4));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [arrayToCSV](https://www.30secondsofcode.org/js/s/array-to-csv)\n",
    "JavaScript, Array, String, Intermediate\n",
    "\n",
    "Converts a 2D array to a comma-separated values (CSV) string.\n",
    "\n",
    "Use `Array.prototype.map()` and `Array.prototype.join(delimiter)` to combine individual 1D arrays (rows) into strings. Use `Array.prototype.join('\\n')` to combine all rows into a CSV string, separating each row with a newline. Omit the second argument, `delimiter`, to use a default delimiter of `,`.\n",
    "\n",
    "---\n",
    "将二维数组转换为逗号分隔值（CSV）字符串。\n",
    "\n",
    "---\n",
    "\n",
    "`\"${x.replace(/\"/g, '\"\"')}\"`把`''`换成`\"\"`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 95,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.756963Z",
     "start_time": "2020-11-30T14:44:13.475Z"
    }
   },
   "outputs": [],
   "source": [
    "const arrayToCSV = (arr, delimiter = ',') =>\n",
    "  arr\n",
    "    .map(v => v.map(x => (isNaN(x) ? `\"${x.replace(/\"/g, '\"\"')}\"` : x)).join(delimiter))\n",
    "    .join('\\n');"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 96,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.761437Z",
     "start_time": "2020-11-30T14:44:13.479Z"
    },
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\"'anlzou'\",\"\"\"anlzou\"\"\",\"a\",\"b\"\n",
      "\"c\",\"d\"\n",
      "\"e\",\"f\"\n",
      "\"a\";\"b\"\n",
      "\"c\";\"d\"\n",
      "\"a\",\"\"\"b\"\" great\"\n",
      "\"c\",3.1415\n"
     ]
    }
   ],
   "source": [
    "console.log(arrayToCSV([[\"'anlzou'\",'\"anlzou\"','a', 'b'], ['c', 'd'], ['e', 'f']]));\n",
    "console.log(arrayToCSV([['a', 'b'], ['c', 'd']], ';'));\n",
    "console.log(arrayToCSV([['a', '\"b\" great'], ['c', 3.1415]]));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [bifurcate](https://www.30secondsofcode.org/js/s/bifurcate)\n",
    "JavaScript, Array, Intermediate\n",
    "\n",
    "Splits values into two groups. If an element in `filter` is truthy, the corresponding element in the collection belongs to the first group; otherwise, it belongs to the second group.\n",
    "\n",
    "Use `Array.prototype.reduce()` and `Array.prototype.push()` to add elements to groups, based on `filter`.\n",
    "\n",
    "---\n",
    "`reduce()` 方法接收一个函数作为累加器，数组中的每个值（从左到右）开始缩减，最终计算为一个值。\n",
    "\n",
    "`reduce()` 可以作为一个高阶函数，用于函数的 compose。\n",
    "\n",
    "**注意**: reduce() 对于空数组是不会执行回调函数的。\n",
    "\n",
    "**语法**\n",
    "```js\n",
    "array.reduce(function(total, currentValue, currentIndex, arr), initialValue)\n",
    "```\n",
    "**参数**\n",
    "\n",
    "- function(total,currentValue, index,arr)\t必需。用于执行每个数组元素的函数。\n",
    "    - total\t必需。初始值, 或者计算结束后的返回值。\n",
    "    - currentValue\t必需。当前元素\n",
    "    - currentIndex\t可选。当前元素的索引\n",
    "    - arr\t可选。当前元素所属的数组对象。\n",
    "- initialValue\t可选。传递给函数的初始值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 97,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.772004Z",
     "start_time": "2020-11-30T14:44:13.483Z"
    }
   },
   "outputs": [],
   "source": [
    "const bifurcate = (arr, filter) =>\n",
    "  arr.reduce((acc, val, i) => (acc[filter[i] ? 0 : 1].push(val), acc), [[], []]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 98,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.772490Z",
     "start_time": "2020-11-30T14:44:13.487Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ [ 'beep', 'boop', 'bar' ], [ 'foo' ] ]\n"
     ]
    }
   ],
   "source": [
    "console.log(bifurcate(['beep', 'boop', 'foo', 'bar'], [true, true, false, true]));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [bifurcateBy](https://www.30secondsofcode.org/js/s/bifurcate-by)\n",
    "JavaScript, Array, Function, Intermediate\n",
    "\n",
    "Splits values into two groups according to a predicate function, which specifies which group an element in the input collection belongs to. If the predicate function returns a truthy value, the collection element belongs to the first group; otherwise, it belongs to the second group.\n",
    "\n",
    "Use `Array.prototype.reduce()` and `Array.prototype.push()` to add elements to groups, based on the value returned by `fn` for each element."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 99,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.772917Z",
     "start_time": "2020-11-30T14:44:13.491Z"
    }
   },
   "outputs": [],
   "source": [
    "const bifurcateBy = (arr, fn) =>\n",
    "  arr.reduce((acc, val, i) => (acc[fn(val, i) ? 0 : 1].push(val), acc), [[], []]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 100,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.784437Z",
     "start_time": "2020-11-30T14:44:13.494Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ [ 'beep', 'boop', 'bar' ], [ 'foo' ] ]\n"
     ]
    }
   ],
   "source": [
    "console.log(bifurcateBy(['beep', 'boop', 'foo', 'bar'], x => x[0] === 'b'));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [countBy](https://www.30secondsofcode.org/js/s/count-by)\n",
    "JavaScript, Array, Object, Intermediate\n",
    "\n",
    "Groups the elements of an array based on the given function and returns the count of elements in each group.\n",
    "\n",
    "Use `Array.prototype.map()` to map the values of an array to a function or property name. Use `Array.prototype.reduce()` to create an object, where the keys are produced from the mapped results."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 101,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.785596Z",
     "start_time": "2020-11-30T14:44:13.498Z"
    }
   },
   "outputs": [],
   "source": [
    "const countBy = (arr, fn) =>\n",
    "  arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val) => {\n",
    "    acc[val] = (acc[val] || 0) + 1;\n",
    "    return acc;\n",
    "  }, {});"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 102,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.786042Z",
     "start_time": "2020-11-30T14:44:13.504Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{ '4': 1, '6': 2 }\n",
      "{ '3': 2, '5': 1 }\n",
      "{ '5': 2, '10': 1 }\n"
     ]
    }
   ],
   "source": [
    "console.log(countBy([6.1, 4.2, 6.3], Math.floor));\n",
    "console.log(countBy(['one', 'two', 'three'], 'length'));\n",
    "console.log(countBy([{ count: 5 }, { count: 10 }, { count: 5 }], x => x.count));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 103,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.797510Z",
     "start_time": "2020-11-30T14:44:13.507Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[Function (anonymous)]\n"
     ]
    }
   ],
   "source": [
    "test = (arr, fn) =>\n",
    "    console.log(typeof fn === 'function' ? fn : val => val[fn]);\n",
    "test(['one', 'two', 'three'], 'length');"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [countOccurrences](https://www.30secondsofcode.org/js/s/count-occurrences)\n",
    "JavaScript, Array, Intermediate\n",
    "\n",
    "Counts the occurrences of a value in an array.\n",
    "\n",
    "Use `Array.prototype.reduce()` to increment a counter each time you encounter the specific value inside the array."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 104,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.798716Z",
     "start_time": "2020-11-30T14:44:13.512Z"
    }
   },
   "outputs": [],
   "source": [
    "// 0， 传递给函数的初始值\n",
    "const countOccurrences = (arr, val) => arr.reduce((a, v) => (v === val ? a + 1 : a), 0);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 105,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.799928Z",
     "start_time": "2020-11-30T14:44:13.515Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3\n"
     ]
    }
   ],
   "source": [
    "console.log(countOccurrences([1, 1, 2, 1, 2, 3], 1));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [flatten](https://www.30secondsofcode.org/js/s/flatten)\n",
    "JavaScript, Array, Intermediate\n",
    "\n",
    "Flattens an array up to the specified depth.\n",
    "\n",
    "Use recursion, decrementing `depth` by 1 for each level of depth. Use `Array.prototype.reduce()` and `Array.prototype.concat()` to merge elements or arrays. Base case, for `depth` equal to `1` stops recursion. Omit the second argument, `depth` to flatten only to a depth of `1` (single flatten)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 106,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.809438Z",
     "start_time": "2020-11-30T14:44:13.518Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Function: flatten]"
      ]
     },
     "execution_count": 106,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "flatten = (arr, depth = 1) =>\n",
    "    arr.reduce((a, v) => a.concat(depth > 1 && Array.isArray(v) ? flatten(v, depth - 1) : v), []);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 107,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.809881Z",
     "start_time": "2020-11-30T14:44:13.521Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 1, 2, 3, 4 ]\n",
      "[ 1, 2, 3, [ 4, 5 ], 6, 7, 8 ]\n",
      "[ 1, 2, [ 3, 4, 4 ], 4, 4, 5 ]\n"
     ]
    }
   ],
   "source": [
    "console.log(flatten([1, [2], 3, 4]));\n",
    "console.log(flatten([1, [2, [3, [4, 5], 6], 7], 8], 2));\n",
    "console.log(flatten([1, [2], [[3,4,4], 4,4], 5]));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [deepFlatten](https://www.30secondsofcode.org/js/s/deep-flatten)\n",
    "JavaScript, Array, Recursion, Intermediate\n",
    "\n",
    "Deep flattens an array.\n",
    "\n",
    "Use recursion. Use `Array.prototype.concat()` with an empty array (`[]`) and the spread operator (`...`) to flatten an array. Recursively flatten each element that is an array."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 108,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.810357Z",
     "start_time": "2020-11-30T14:44:13.525Z"
    }
   },
   "outputs": [],
   "source": [
    "const deepFlatten = arr => [].concat(...arr.map(v => (Array.isArray(v) ? deepFlatten(v) : v)));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 109,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.810787Z",
     "start_time": "2020-11-30T14:44:13.527Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[\n",
      "  1, 2, 3, 4,\n",
      "  4, 4, 4, 5\n",
      "]\n"
     ]
    }
   ],
   "source": [
    "console.log(deepFlatten([1, [2], [[3,4,4], 4,4], 5]));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [differenceBy](https://www.30secondsofcode.org/js/s/difference-by)\n",
    "JavaScript, Array, Function, Intermediate\n",
    "\n",
    "Returns the difference between two arrays, after applying the provided function to each array element of both.\n",
    "\n",
    "Create a `Set` by applying `fn` to each element in `b`, then use `Array.prototype.map()` to apply `fn` to each element in `a`, then `Array.prototype.filter()`\n",
    "\n",
    "---\n",
    "数组a中不含数组b的元素"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 110,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.824899Z",
     "start_time": "2020-11-30T14:44:13.530Z"
    }
   },
   "outputs": [],
   "source": [
    "const differenceBy = (a, b, fn) => {\n",
    "  const s = new Set(b.map(fn));\n",
    "  return a.map(fn).filter(el => !s.has(el));\n",
    "};"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 111,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.825360Z",
     "start_time": "2020-11-30T14:44:13.534Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 1 ]\n",
      "[ 2 ]\n"
     ]
    }
   ],
   "source": [
    "console.log(differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor));\n",
    "console.log(differenceBy([{ x: 2 }, { x: 1 }], [{ x: 1 }], v => v.x));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [differenceWith](https://www.30secondsofcode.org/js/s/difference-with)\n",
    "JavaScript, Array, Function, Intermediate\n",
    "\n",
    "Filters out all values from an array for which the comparator function does not return `true`.\n",
    "\n",
    "Use `Array.prototype.filter()` and `Array.prototype.findIndex()` to find the appropriate values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 112,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.830883Z",
     "start_time": "2020-11-30T14:44:13.537Z"
    }
   },
   "outputs": [],
   "source": [
    "const differenceWith = \n",
    "      (arr, val, comp) => arr.filter(\n",
    "          a => val.findIndex(b => comp(a, b)) === -1\n",
    "      );"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 113,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.831396Z",
     "start_time": "2020-11-30T14:44:13.540Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 1, 1.2 ]\n"
     ]
    }
   ],
   "source": [
    "console.log(differenceWith([1, 1.2, 1.5, 3, 0], \n",
    "                           [1.9, 3, 0], \n",
    "                           (a, b) => Math.round(a) === Math.round(b)));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [dropRightWhile](https://www.30secondsofcode.org/js/s/drop-right-while)\n",
    "JavaScript, Array, Function, Intermediate\n",
    "\n",
    "Removes elements from the end of an array until the passed function returns `true`. Returns the remaining elements in the array.\n",
    "\n",
    "Loop through the array, using `Array.prototype.slice()` to drop the last element of the array until the returned value from the function is `true`. Returns the remaining elements."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 114,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.831823Z",
     "start_time": "2020-11-30T14:44:13.543Z"
    }
   },
   "outputs": [],
   "source": [
    "//默认已经排序\n",
    "\n",
    "const dropRightWhile = (arr, func) => {\n",
    "    let rightIndex = arr.length;\n",
    "    while (rightIndex-- && !func(arr[rightIndex]));\n",
    "    return arr.slice(0, rightIndex + 1);\n",
    "};"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 115,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.832266Z",
     "start_time": "2020-11-30T14:44:13.546Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 1, 2 ]\n"
     ]
    }
   ],
   "source": [
    "console.log(dropRightWhile([1, 2, 3, 4], n => n < 3));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 116,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.841423Z",
     "start_time": "2020-11-30T14:44:13.549Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Function: dropRightWhileSort]"
      ]
     },
     "execution_count": 116,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "//版排序\n",
    "\n",
    "dropRightWhileSort = (arr, func) => {\n",
    "    //扩展运算符，深复制，新的对象\n",
    "    arrSort = [...arr].sort();\n",
    "    let rightIndex = arrSort.length;\n",
    "    while (rightIndex-- && !func(arrSort[rightIndex]));\n",
    "    return arrSort.slice(0, rightIndex + 1);\n",
    "};"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 117,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.841857Z",
     "start_time": "2020-11-30T14:44:13.552Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 1, 3 ]\n"
     ]
    }
   ],
   "source": [
    "console.log(dropRightWhileSort([1, 5, 3, 4], n => n < 4));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [dropLeftWhile](https://www.30secondsofcode.org/js/s/drop-while)\n",
    "JavaScript, Array, Function, Intermediate\n",
    "\n",
    "Removes elements in an array until the passed function returns `true`. Returns the remaining elements in the array.\n",
    "\n",
    "Loop through the array, using `Array.prototype.slice()` to drop the first element of the array until the returned value from the function is `true`. Returns the remaining elements.\n",
    "\n",
    "---\n",
    "**定义和用法**\n",
    "`slice()` 方法可从已有的数组中返回选定的元素。\n",
    "\n",
    "`slice()`方法可提取字符串的某个部分，并以新的字符串返回被提取的部分。\n",
    "\n",
    "**注意**： `slice()` 方法不会改变原始数组。\n",
    "\n",
    "**语法**\n",
    "```js\n",
    "array.slice(start, end)\n",
    "```\n",
    "**参数**\n",
    "\n",
    "|参数|\t描述|\n",
    "|:---|:---|\n",
    "|start|\t可选。规定从何处开始选取。如果是负数，那么它规定从数组尾部开始算起的位置。也就是说，-1 指最后一个元素，-2 指倒数第二个元素，以此类推。|\n",
    "|end|\t可选。规定从何处结束选取。该参数是数组片断结束处的数组下标。如果没有指定该参数，那么切分的数组包含从 start 到数组结束的所有元素。如果这个参数是负数，那么它规定的是从数组尾部开始算起的元素。|\n",
    "\n",
    "**返回值**\n",
    "\n",
    "|Type|\t描述|\n",
    "|:---|:---|\n",
    "|Array|\t返回一个新的数组，包含从 start 到 end （不包括该元素）的 arrayObject 中的元素。|"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 118,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.851579Z",
     "start_time": "2020-11-30T14:44:13.556Z"
    }
   },
   "outputs": [],
   "source": [
    "const dropLeftWhile = (arr, func) => {\n",
    "    while (arr.length > 0 && !func(arr[0])) arr = arr.slice(1);\n",
    "    return arr;\n",
    "};"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 119,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.852752Z",
     "start_time": "2020-11-30T14:44:13.559Z"
    }
   },
   "outputs": [],
   "source": [
    "const dropLeftWhileSort = (arr, func) => {\n",
    "    //扩展运算符，深复制，新的对象\n",
    "    arrSort = [...arr].sort();\n",
    "    while (arrSort.length > 0 && !func(arrSort[0])) arrSort = arrSort.slice(1);\n",
    "    return arrSort;\n",
    "};"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 120,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.860665Z",
     "start_time": "2020-11-30T14:44:13.562Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 3, 4 ]\n",
      "[ 3, 4, 5 ]\n"
     ]
    }
   ],
   "source": [
    "console.log(dropLeftWhile([1, 2, 3, 4], n => n >= 3));\n",
    "\n",
    "console.log(dropLeftWhileSort([1, 3, 5, 4], n => n >= 3));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [filterNonUniqueBy](https://www.30secondsofcode.org/js/s/filter-non-unique-by)\n",
    "JavaScript, Array, Function, Intermediate\n",
    "\n",
    "Filters out the non-unique values in an array, based on a provided comparator function.\n",
    "\n",
    "Use `Array.prototype.filter()` and `Array.prototype.every()` for an array containing only the unique values, based on the comparator function, `fn`. The comparator function takes four arguments: the values of the two elements being compared and their indexes."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [filterNonUniqueBy](https://www.30secondsofcode.org/js/s/filter-non-unique-by)\n",
    "JavaScript, Array, Function, Intermediate\n",
    "\n",
    "Filters out the non-unique values in an array, based on a provided comparator function.\n",
    "\n",
    "Use `Array.prototype.filter()` and `Array.prototype.every()` for an array containing only the unique values, based on the comparator function, `fn`. The comparator function takes four arguments: the values of the two elements being compared and their indexes.\n",
    "\n",
    "---\n",
    "`id` 只出现一次的对象"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 121,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.861877Z",
     "start_time": "2020-11-30T14:44:13.567Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Function: filterNonUniqueBy]"
      ]
     },
     "execution_count": 121,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "filterNonUniqueBy = (arr, fn) =>\n",
    "    arr.filter((v, i) => arr.every((x, j) => (i === j) === fn(v, x, i, j)));//有无i,j都可以"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 122,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.863000Z",
     "start_time": "2020-11-30T14:44:13.570Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ { id: 1, value: 'b' }, { id: 3, value: 'c' }, { id: 2, value: 'd' } ]\n"
     ]
    }
   ],
   "source": [
    "console.log(filterNonUniqueBy(\n",
    "  [\n",
    "    { id: 0, value: 'a' },\n",
    "    { id: 1, value: 'b' },\n",
    "    { id: 3, value: 'c' },\n",
    "    { id: 2, value: 'd' },\n",
    "    { id: 0, value: 'e' }\n",
    "  ],\n",
    "  (a, b) => a.id == b.id\n",
    "));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [forEachRight](https://www.30secondsofcode.org/js/s/for-each-right)\n",
    "JavaScript, Array, Function, Intermediate\n",
    "\n",
    "Executes a provided function once for each array element, starting from the array's last element.\n",
    "\n",
    "Use` Array.prototype.slice()` to clone the given array, `Array.prototype.reverse()` to reverse it and `Array.prototype.forEach()` to iterate over the reversed array.\n",
    "\n",
    "---\n",
    "回调(callback)：回调就是一个在另外一个函数执行完后要执行的函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 123,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.864133Z",
     "start_time": "2020-11-30T14:44:13.574Z"
    }
   },
   "outputs": [],
   "source": [
    "const forEachRight = (arr, callback) =>\n",
    "  arr\n",
    "    .slice()\n",
    "    .reverse()\n",
    "    .forEach(callback);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 124,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.872330Z",
     "start_time": "2020-11-30T14:44:13.577Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4\n",
      "3\n",
      "2\n",
      "1\n"
     ]
    }
   ],
   "source": [
    "forEachRight([1, 2, 3, 4], val => console.log(val));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [frequencies](https://www.30secondsofcode.org/js/s/frequencies)\n",
    "JavaScript, Array, Intermediate\n",
    "\n",
    "Returns an object with the unique values of an array as keys and their frequencies as the values.\n",
    "\n",
    "Use `Array.prototype.reduce()` to map unique values to an object's keys, adding to existing keys every time the same value is encountered.\n",
    "\n",
    "---\n",
    "frequencies：频率"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 150,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-12-03T14:01:02.945633Z",
     "start_time": "2020-12-03T14:01:02.180Z"
    }
   },
   "outputs": [
    {
     "ename": "SyntaxError",
     "evalue": "Identifier 'frequencies' has already been declared",
     "output_type": "error",
     "traceback": [
      "evalmachine.<anonymous>:1",
      "var frequencies = arr =>",
      "^",
      "",
      "SyntaxError: Identifier 'frequencies' has already been declared",
      "    at evalmachine.<anonymous>:1:1",
      "    at Script.runInThisContext (vm.js:131:20)",
      "    at Object.runInThisContext (vm.js:297:38)",
      "    at run ([eval]:1054:15)",
      "    at onRunRequest ([eval]:888:18)",
      "    at onMessage ([eval]:848:13)",
      "    at process.emit (events.js:315:20)",
      "    at emit (internal/child_process.js:881:12)",
      "    at processTicksAndRejections (internal/process/task_queues.js:85:21)"
     ]
    }
   ],
   "source": [
    "var frequencies = arr =>\n",
    "  arr.reduce((a, v) => {\n",
    "    a[\"\"+v] = a[\"\"+v] ? a[\"\"+v] + 1 : 1;\n",
    "    return a;\n",
    "  }, {});"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 144,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-12-03T13:59:42.896043Z",
     "start_time": "2020-12-03T13:59:42.157Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{ a: 4, b: 2, c: 1 }\n"
     ]
    }
   ],
   "source": [
    "console.log(frequencies(['a', 'b', 'a', 'c', 'a', 'a', 'b']));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [groupBy](https://www.30secondsofcode.org/js/s/group-by)\n",
    "JavaScript, Array, Object, Intermediate\n",
    "\n",
    "Groups the elements of an array based on the given function.\n",
    "\n",
    "Use `Array.prototype.map()` to map the values of an array to a function or property name. Use `Array.prototype.reduce()` to create an object, where the keys are produced from the mapped results."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 127,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.890286Z",
     "start_time": "2020-11-30T14:44:13.586Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Function: groupBy]"
      ]
     },
     "execution_count": 127,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "groupBy = (arr, fn) =>\n",
    "    arr.map(typeof fn === 'function' ?  fn : val => val[fn])\n",
    "    .reduce((acc, val, i) =>{\n",
    "        acc[val] = (acc[val] || []).concat(arr[i]);\n",
    "        return acc;\n",
    "    },{});"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 128,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.891439Z",
     "start_time": "2020-11-30T14:44:13.589Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{ '4': [ 4.2 ], '6': [ 6.1, 6.3 ] }\n",
      "{ '3': [ 'one', 'two' ], '5': [ 'three' ] }\n"
     ]
    }
   ],
   "source": [
    "console.log(groupBy([6.1, 4.2, 6.3], Math.floor));\n",
    "console.log(groupBy(['one', 'two', 'three'], 'length'));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [haveSameContents](https://www.30secondsofcode.org/js/s/have-same-contents)\n",
    "JavaScript, Array, Intermediate\n",
    "\n",
    "Returns `true` if two arrays contain the same elements regardless of order, `false` otherwise.\n",
    "\n",
    "Use a `for...of` loop over a `Set` created from the values of both arrays. Use `Array.prototype.filter()` to compare the amount of occurrences of each distinct value in both arrays. Return `false` if the counts do not match for any element, `true` otherwise.\n",
    "\n",
    "--- \n",
    "contents：[名词] 内容, 目录, 含量, 篇目"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 129,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.892621Z",
     "start_time": "2020-11-30T14:44:13.592Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Function: haveSameContents]"
      ]
     },
     "execution_count": 129,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "haveSameContents = (a, b) =>{\n",
    "    for(v of new Set([...a, ...b]))\n",
    "        if(a.filter(e => e === v).length !== b.filter(e => e === v).length) return false;\n",
    "    return true;\n",
    "};"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 130,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.911804Z",
     "start_time": "2020-11-30T14:44:13.595Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "true\n",
      "false\n"
     ]
    }
   ],
   "source": [
    "console.log(haveSameContents([1,2,3],[3,2,1]));\n",
    "console.log(haveSameContents([2,1],[3,2,1,5]));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [indexOfAll](https://www.30secondsofcode.org/js/s/index-of-all)\n",
    "JavaScript, Array, Intermediate\n",
    "\n",
    "Returns all indices of `val` in an array. If `val` never occurs, returns `[]`.\n",
    "\n",
    "Use `Array.prototype.reduce()` to loop over elements and store indices for matching elements. Return the array of indices.\n",
    "\n",
    "---\n",
    "找出所有该值的下标\n",
    "\n",
    "`[]`：为初始值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 131,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.915928Z",
     "start_time": "2020-11-30T14:44:13.599Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Function: indexOfAll]"
      ]
     },
     "execution_count": 131,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "indexOfAll = (arr, val) => arr\n",
    "    .reduce((acc, el, i) => (el === val ? [...acc, i] : acc), []);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 132,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.917087Z",
     "start_time": "2020-11-30T14:44:13.602Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 0, 4, 8 ]\n",
      "[]\n"
     ]
    }
   ],
   "source": [
    "console.log(indexOfAll([1,2,3,4,1,3,2,4,1],1));\n",
    "console.log(indexOfAll([1, 2, 3], 4));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [initialize2DArray](https://www.30secondsofcode.org/js/s/initialize2-d-array)\n",
    "JavaScript, Array, Intermediate\n",
    "\n",
    "Initializes a 2D array of given width and height and value.\n",
    "\n",
    "Use `Array.prototype.map()` to generate h rows where each is a new array of size w initialize with value. If the value is not provided, default to `null`.\n",
    "\n",
    "---\n",
    "`from()`\t通过给定的对象中创建一个数组。\n",
    "\n",
    "**定义和用法**\n",
    "\n",
    "from() 方法用于通过拥有 length 属性的对象或可迭代的对象来返回一个数组。\n",
    "\n",
    "如果对象是数组返回 true，否则返回 false。\n",
    "\n",
    "**语法**\n",
    "```js\n",
    "Array.from(object, mapFunction, thisValue)\n",
    "```\n",
    "\n",
    "|参数|\t描述|\n",
    "|:---|:---|\n",
    "|object|\t必需，要转换为数组的对象。|\n",
    "|mapFunction|\t可选，数组中每个元素要调用的函数。|\n",
    "|thisValue|\t可选，映射函数(mapFunction)中的 this 对象。|\n",
    "\n",
    "`{ length: h }`: 对象"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 133,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.918263Z",
     "start_time": "2020-11-30T14:44:13.605Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Function: initialize2DArray]"
      ]
     },
     "execution_count": 133,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "initialize2DArray = (w, h, val = null) =>\n",
    "    Array.from({ length: h }).map(() => Array.from({ length: w }).fill(val));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 134,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.919413Z",
     "start_time": "2020-11-30T14:44:13.608Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ [ 1, 1 ], [ 1, 1 ], [ 1, 1 ] ]\n"
     ]
    }
   ],
   "source": [
    "console.log(initialize2DArray(2,3,1));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [initializeArrayWithRange](https://www.30secondsofcode.org/js/s/initialize-array-with-range)\n",
    "JavaScript, Array, Math, Intermediate\n",
    "\n",
    "Initializes an array containing the numbers in the specified range where `start` and `end` are inclusive with their common difference `step`.\n",
    "\n",
    "Use `Array.from()` to create an array of the desired length, `(end - start + 1)/step`, and a map function to fill it with the desired values in the given range. You can omit `start` to use a default value of `0`. You can omit `step` to use a default value of `1`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 135,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.937435Z",
     "start_time": "2020-11-30T14:44:13.612Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Function: initializeArrayWithRange]"
      ]
     },
     "execution_count": 135,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "initializeArrayWithRange = (end, start = 0, step = 1) =>\n",
    "    Array.from({ length: Math.ceil((end - start + 1) / step) },(v, i) => i * step + start);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 136,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.938572Z",
     "start_time": "2020-11-30T14:44:13.615Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 0, 1, 2, 3, 4, 5 ]\n",
      "[ 3, 4, 5, 6, 7 ]\n",
      "[ 0, 2, 4, 6, 8 ]\n"
     ]
    }
   ],
   "source": [
    "console.log(initializeArrayWithRange(5));\n",
    "console.log(initializeArrayWithRange(7, 3));\n",
    "console.log(initializeArrayWithRange(9, 0, 2));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [initializeArrayWithRangeRight](https://www.30secondsofcode.org/js/s/initialize-array-with-range-right)\n",
    "JavaScript, Array, Math, Intermediate\n",
    "\n",
    "Initializes an array containing the numbers in the specified range (in reverse) where `start` and `end` are inclusive with their common difference `step`.\n",
    "\n",
    "Use `Array.from(Math.ceil((end+1-start)/step))` to create an array of the desired length(the amounts of elements is equal to `(end-start)/step` or `(end+1-start)/step` for inclusive end), `Array.prototype.map()` to fill with the desired values in a range. You can omit `start` to use a default value of `0`. You can omit `step` to use a default value of `1`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 137,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.951070Z",
     "start_time": "2020-11-30T14:44:13.618Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Function: initializeArrayWithRangeRight]"
      ]
     },
     "execution_count": 137,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "initializeArrayWithRangeRight = (end, start = 0, step = 1) =>\n",
    "  Array.from({ length: Math.ceil((end + 1 - start) / step) }).map(\n",
    "    (v, i, arr) => (arr.length - i - 1) * step + start\n",
    "  );"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 138,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-11-30T14:44:14.952300Z",
     "start_time": "2020-11-30T14:44:13.620Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 5, 4, 3, 2, 1, 0 ]\n",
      "[ 7, 6, 5, 4, 3 ]\n",
      "[ 8, 6, 4, 2, 0 ]\n"
     ]
    }
   ],
   "source": [
    "console.log(initializeArrayWithRangeRight(5));\n",
    "console.log(initializeArrayWithRangeRight(7, 3));\n",
    "console.log(initializeArrayWithRangeRight(9, 0, 2));"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Javascript (Node.js)",
   "language": "javascript",
   "name": "javascript"
  },
  "language_info": {
   "file_extension": ".js",
   "mimetype": "application/javascript",
   "name": "javascript",
   "version": "13.13.0"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "347px"
   },
   "toc_section_display": true,
   "toc_window_display": false
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
